import { Asset, AssetManager, Label, Layout, Node, Prefab, RichText, Sprite, SpriteFrame, UITransform, Vec2, Vec3, assetManager, director, instantiate, sp, v2, v3 } from "cc";
import { DEV, JSB } from "cc/env";

export enum ImageFillMode {
    None,
    BorderScale,
    FullScale
}

export enum FpsMode {
    Auto = -1,
    High = 60,
    Low = 45
}
export const dir2crd = [
    v2(1, 0),
    v2(1, -1),   //实际坐标移动和轮盘指向的y轴走向相反
    v2(0, -1),
    v2(-1, -1),
    v2(-1, 0),
    v2(-1, 1),
    v2(0, 1),
    v2(1, 1),
]
export const enum Direction {
    none = -1,
    right = 0,
    rightUp,
    up,
    leftUp,
    left,
    leftDown,
    down,
    rightDown
}

//设置默认图片
var defaultImage: SpriteFrame;
var resVersion: string;
export function initResLoader(defaultImg: SpriteFrame, version: string) {
    defaultImage = defaultImg;
    resVersion = version;
}

//延时
export async function delay(milliseconds: number) {
    return new Promise((resolve, reject) =>
        setTimeout(() => resolve(null), milliseconds));
}
export function randomOf(min: number, max: number, func: (t: number) => number = t => t) {
    return func(Math.random()) * (max - min) + min;
}
export function randomElement<T>(a: Array<T>) {
    if (!a || a.length == 0)
        return null;
    return a[Math.floor(Math.random() * a.length)];
}
/**将oldRoot本地坐标系下的pos坐标转换到newRoot本地坐标系下的坐标 */
export function TransPos(oldRoot: Node, newRoot: Node, pos: Vec3) {
    return newRoot.getComponent(UITransform).convertToNodeSpaceAR(oldRoot.getComponent(UITransform).convertToWorldSpaceAR(pos));
}
export function TransPos2(oldRoot: Node, newRoot: Node, pos: Vec3) {
    return newRoot.getComponent(UITransform).convertToNodeSpaceAR(oldRoot.getComponent(UITransform).convertToWorldSpaceAR(pos));
}
export function hasStr(str: string, subStr: string) {
    return str.indexOf(subStr) != -1;
}
export function time2str(time: number) {
    let min = Math.floor(time / 60);
    let sec = Math.floor(time % 60);
    if (sec < 10) {
        return `${min}:0${sec}`;
    }
    else {
        return `${min}:${sec}`;
    }
}
export function getChoice(prob: number[], element: number[]) {
    if (prob.length != element.length) {
        console.error("概率数组和元素数组不匹配");
        return;
    }
    let probCnt = 0;
    let rand = Math.random();
    let allWei = 0;
    prob.forEach(e => allWei += e);
    for (let i = 0; i < prob.length; i++) {
        let e = element[i];
        let p = prob[i] / allWei;
        if (rand <= probCnt + p)
            return e;
        probCnt += p;
    }
    return element[element.length - 1];
}
//函数截流
export function throttle(fn: Function, wait: number) {
    var timer = null;
    return function () {
        var context = this;
        var args = arguments;
        if (!timer) {
            timer = setTimeout(function () {
                fn.apply(context, args);
                timer = null;
            }, wait);
        }
    }
}


//可取消的promise
export function promiseCancelable(promise: Promise<any>): { promise: Promise<any>, cancel?: Function } {
    let hasCanceled = false;
    const wrappedPromise = new Promise((resolve, reject) => {
        promise.then((val) =>
            hasCanceled ? reject({ isCanceled: true }) : resolve(val)
        );
        promise.catch((error) =>
            hasCanceled ? reject({ isCanceled: true }) : reject(error)
        );
    });
    return {
        promise: wrappedPromise,
        cancel() {
            hasCanceled = true;
        },
    };
};

//是否同一天
export function isSameDay(time1: number, time2: number): boolean {
    return new Date(time1).toDateString() == new Date(time2).toDateString();
}

//加载bundle包
export async function loadBundle(name: string): Promise<AssetManager.Bundle> {
    return new Promise<AssetManager.Bundle>((resolve, reject) => {
        let version = (DEV || name != "remoteAsset" || !isApp()) ? "" : resVersion;
        assetManager.loadBundle(name, { version: version }, (err, bundle: AssetManager.Bundle) => {
            if (err) {
                console.error("loadBundle error", err);
                reject();
            } else {
                resolve(bundle);
            }
        });
    });
}

export async function preloadBundles() {
    console.warn("preloadBundles start")
    let bundles = ["gameAsset", "remoteAsset"];
    let all = [];
    for (let i = 0; i < bundles.length; i++) {
        const name = bundles[i];
        all.push(loadBundle(name));
    }
    await Promise.all(all);
    console.warn("preloadBundles end")
}


//加载资源
export async function loadRes<T extends Asset>(type: new () => T, path: string): Promise<T> {
    if (!path) return null;
    let bundles = ["resources", "artres"];
    for (let i = 0; i < bundles.length; i++) {
        const name = bundles[i];
        let res = await loadBundleRes(type, path, name);
        if (res != null) {
            return res;
        }
    }
    console.warn("loadRes err", path);
    return null;
}
//预加载资源
export async function preloadRes<T extends Asset>(type: new () => T, path: string): Promise<boolean> {
    if (!path) return null;
    let bundles = ["resources", "artres"];
    for (let i = 0; i < bundles.length; i++) {
        const name = bundles[i];
        let res = await preloadBundleRes(type, path, name);
        if (res != null) {
            return res;
        }
    }
    console.warn("loadRes err", path);
    return null;
}

//加载bundle资源
export async function loadBundleRes<T extends Asset>(type: new () => T, path: string, bundleName: string): Promise<T> {
    let promise = new Promise<T>(async resolve => {
        let res = getRes(type, path, bundleName);
        if (res != null) {
            resolve(res);
            return;
        }
        let bundle = assetManager.getBundle(bundleName);
        if (!bundle) {
            bundle = await loadBundle(bundleName);
        }
        if (!bundle.getInfoWithPath(path)) {
            resolve(null);
        } else {
            bundle.load(path, <any>type, (err, asset) => {
                resolve(err ? null : asset as T);
            });
        }
    })
    return promise;
}

export async function preloadBundleRes<T extends Asset>(type: new () => T, path: string, bundleName: string): Promise<boolean> {
    let promise = new Promise<boolean>(async resolve => {
        let res = getRes(type, path, bundleName);
        if (res != null) {
            resolve(true);
            return;
        }
        let bundle = assetManager.getBundle(bundleName);
        if (!bundle) {
            bundle = await loadBundle(bundleName);
        }
        if (!bundle.getInfoWithPath(path)) {
            resolve(null);
        } else {
            bundle.preload(path, <any>type, (err, asset) => {
                resolve(err ? false : true);
            });
        }
    })
    return promise;
}

export function getRes<T extends Asset>(type: new () => T, path: string, bundle: string): T {
    if (!path) return null;
    let uuid = path2uuid(type, path, bundle);
    if (!uuid) {
        return null;
    }
    let res = assetManager.assets.get(uuid);
    return res ? res as T : null;
}

export async function loadNode(path: string, parent?: Node) {
    if (!path) return null;
    let promise = new Promise<Node>(async resolve => {
        let prefab = await loadRes(Prefab, path);
        if (!prefab) resolve(null);
        else {
            let node = instantiate(prefab);
            parent && (node.parent = parent);
            node.position = v3();
            node.active = true;
            resolve(node);
        }
    })
    return promise;
}

//根据文件路径获得uuid
export function path2uuid<T extends Asset>(type: new () => T, path: string, bundle: string): string {
    let bundles = assetManager.bundles;
    if (bundles.has(bundle)) {
        var bundleAsset = bundles.get(bundle);
        var info = bundleAsset.getInfoWithPath(path, type as any);
        if (info && info.redirect) {
            if (!bundles.has(info.redirect)) throw new Error(`you need to load bundle ${info.redirect} first`);
            bundleAsset = bundles.get(info.redirect);
            return bundleAsset.getAssetInfo(info.uuid).uuid;
        }
        return info.uuid;
    }
}

//比较版本号(1表示v1比v2新，0表示相同，-1表示比v2要老)
export function compareVersion(v1, v2) {
    v1 = v1.split('.')
    v2 = v2.split('.')
    var len = Math.max(v1.length, v2.length)

    while (v1.length < len) {
        v1.push('0')
    }
    while (v2.length < len) {
        v2.push('0')
    }

    for (var i = 0; i < len; i++) {
        var num1 = parseInt(v1[i])
        var num2 = parseInt(v2[i])

        if (num1 > num2) {
            return 1
        } else if (num1 < num2) {
            return -1
        }
    }
    return 0
}


//加载spine
export async function loadSpine(path: string): Promise<sp.SkeletonData> {
    if (!path) return null;
    let res = await loadRes(sp.SkeletonData, path);
    return res;
}

//加载图片资源，修复因为异步问题图片显示不对的bug
export async function loadImage(target: Sprite, url: string, scaleMode: ImageFillMode = ImageFillMode.None, removeLoad: boolean = true) {
    if (!target || !target.node) return;
    if (removeLoad) {
        target.spriteFrame = null;
    }
    target["url"] = url;
    let res = await loadRes(SpriteFrame, url);
    if (res && url && target["url"].indexOf(res["_name"]) != -1 && target["url"] == url) {
        target.spriteFrame = res;
    } else if (!res) {
        target.spriteFrame = defaultImage;
    }
    scaleImage(target, scaleMode);
}

//加载远程资源
export async function loadRemote(url: string, extension: string = null, cacheMode: boolean = true): Promise<any> {
    let promise = new Promise<any>(resolve => {
        if (!url) {
            resolve(null);
            return;
        }
        let ext = extension ? { ext: extension, cacheEnabled: cacheMode } : { cacheEnabled: cacheMode };
        assetManager.loadRemote(url, ext, (err, asset) => {
            resolve(err ? null : asset);
        });
    });
    return promise;
}

export function findConfig<T>(config: T[], filter: (item: T) => boolean): T {
    for (let i = 0; i < config.length; ++i) {
        if (filter(config[i])) {
            return config[i];
        }
    }
    return null;
}

//等比缩放图片
export function scaleImage(sprite: Sprite, scaleMode: ImageFillMode = ImageFillMode.BorderScale): void {
    if (!sprite.node || !sprite.spriteFrame || scaleMode == ImageFillMode.None) return;
    if (sprite.sizeMode != Sprite.SizeMode.CUSTOM) {
        console.warn("scaleImage sizemode error,node name:" + sprite.node.name);
    }
    sprite.trim = false;//去除空白区域选项屏蔽
    let size = sprite.spriteFrame.getOriginalSize();
    let spriteWidth = sprite.node.getComponent(UITransform).width;
    let spriteHeight = sprite.node.getComponent(UITransform).height;
    let widthRatio = spriteWidth / size.width;
    let heightRatio = spriteHeight / size.height;
    let scale: number = scaleMode == ImageFillMode.BorderScale ? Math.min(widthRatio, heightRatio) : Math.max(widthRatio, heightRatio);
    let sw = scale * size.width / spriteWidth;
    let sh = scale * size.height / spriteHeight;
    sprite.node.setScale(sw, sh, 1);
}

//随机种子随机数
let randomSeed: number = 5;
export function seedRandom(seed?: number): number {
    if (seed != undefined) {
        randomSeed = seed;
    }
    randomSeed = (randomSeed * 9301 + 49297) % 233280;
    let rnd = randomSeed / 233280.0;
    return rnd;
}

export function seedRandomInt(min: number, max: number, seed?: number): number {
    max = max || 1;
    min = min || 0;
    let rnd = seedRandom(seed);
    return Math.floor(min + rnd * (max - min));   // Math.ceil实现取整功能，可以根据需要取消取整
}

//放到别的容器
export function toParent(node: Node, parent: Node): void {
    if (parent == node.parent) {
        return;
    }
    let pos = convertPosition(node, parent);
    node.parent = parent;
    node.setPosition(v3(pos.x, pos.y, 0));
}

//获取相对坐标
export function convertPosition(nodeOrWorldPos: Node | Vec2, parent: Node): Vec2 {
    let pos: Vec3 = v3();
    if (nodeOrWorldPos instanceof Node) {
        if (nodeOrWorldPos.isValid && nodeOrWorldPos.parent) {
            pos = nodeOrWorldPos.parent.getComponent(UITransform).convertToWorldSpaceAR(nodeOrWorldPos.position);
        }
    } else {
        pos = v3(nodeOrWorldPos.x, nodeOrWorldPos.y);
    }
    pos = parent.getComponent(UITransform).convertToNodeSpaceAR(pos);
    return v2(pos.x, pos.y);
}

//立马更新
export function updateNow(node: Node) {
    let label = node.getComponent(Label);
    if (label) {
        label["_forceUpdateRenderData"]();
        return;
    }
    let richText = node.getComponent(RichText);
    if (richText) {
        node["_activeInHierarchy"] = true;
        richText["_updateRichText"]();
        return;
    }
    let layout = node.getComponent(Layout);
    if (layout) {
        layout.updateLayout()
        return;
    }
}


//执行函数
export function invokeCallback(cb, ...arg: any[]) {
    if (!!cb && typeof cb === 'function') {
        cb.apply(null, Array.prototype.slice.call(arguments, 1));
    }
}

/**随机int(左闭右开)*/
export function randomInt(min, max) {
    return Math.floor(randomNumber(min, max));
}

export function randomNumber(min, max) {
    return Math.random() * (max - min) + min;
}

//范围内取值
export function rangeValue(value, min, max) {
    value = Math.max(min, value);
    value = Math.min(max, value);
    return value;
}

/**二维数组转置 */
export function switchMatt(arr: any[][]) {
    let result = arr[0].map(function (col, i) {
        return arr.map(function (row) {
            return row[i];
        })
    });
    return result;
}

/**
 * 洗牌算法
 * @param arr 数组
 * @param flag 是否影响原数组
 * @returns 
 */
export function shuffle(arr: any[], isEffectSrc = false) {
    let newArr = [];
    let cloneArr: Function = (arr: any[]) => {
        return arr.slice(0);
    }
    isEffectSrc ? (newArr = arr) : (newArr = cloneArr(arr));
    let getRandom: Function = (min, max) => {
        return Math.floor(Math.random() * (max - min + 1) + min);
    }
    for (let i = 0; i < newArr.length; i++) {
        let j = getRandom(0, i);
        let temp = newArr[i];
        newArr[i] = newArr[j];
        newArr[j] = temp;
    }
    return newArr;
}

/**
 * 随机权重
 * @param element 元素组
 * @param weight 权重组
 * @returns 返回随机元素的索引
 */
export function randomByWeight(element: any[], weight: number[]): number {
    if (element.length != weight.length) {
        console.error('权重随机输入参数长度不等');
        return;
    }
    let sum = 0;
    weight.forEach(v => sum += v);
    let rand = Math.random() * sum;
    let tmp = weight[0];
    for (let i = 1; i < weight.length; i++) {
        if (rand < tmp) return i - 1;
        tmp += weight[i];
    }
    return weight.length - 1;
}

/**获得两个时间戳的差值 单位ms */
export function getDeltaTime(curTime: number, lastTime: number): number {
    return curTime - lastTime;
}

export function getBit(value: number, bit: number = 1): string {
    return value.toFixed(bit);
}

/**格式化自动换行 */
export function formatStrEnter(str: string, format: number = 10, isRichtext: boolean = false): string {
    let enter: string = isRichtext ? '<br/>' : '\n';
    let sig: string[] = [];
    let count: number = 0;
    let start = 0;
    for (let i = 0; i < str.length; i++) {
        if (str.charCodeAt(i) > 255) {
            count += 2;
        }
        else count++;
        if (count >= format) {
            sig.push(str.slice(start, i));
            start = i;
            count = 0;
        }
    }
    sig.push(str.slice(start));
    let result: string = '';
    for (let i = 0, l = sig.length; i < l; i++) {
        result += sig[i];
        if (i < l - 1) result += enter;
    }
    return result;
}

/**格式化长名字 */
export function formatLongName(str: string, limit: number = 0): string {
    let len = 0;
    for (let i = 0; i < str.length; i++) {
        if (str.charCodeAt(i) > 255) {
            len += 2;
        } else {
            len++;
        }
        if (len >= limit) {
            str = str.slice(0, i + 1) + '...';
            break;
        }
    }

    return str;
}

/**格式化数值逗号 */
export function formatNumberDot(num: number) {
    let data = (num || 0).toString();
    let result = '';
    while (data.length > 3) {
        result = ',' + data.slice(-3) + result;
        data = data.slice(0, data.length - 3);
    }
    if (data) { result = data + result; }
    return result;
}

/**格式化时间 返回字符串’w天x小时y分钟z秒‘*/
export function formatTimeHMS_str(time: number, isChinese: boolean = true, isDay: boolean = false, length: number = 0) {
    time = ~~time;
    let data = formatTimeHMS(time);
    let res = '';
    let len = 0;
    if (data.hour > 23 && isDay) {
        let days = ~~(data.hour / 24);
        res += days + (isChinese ? '天' : 'd');
        data.hour -= days * 24;
        len++;
    }
    if (data.hour > 0 && (!length || len < length)) {
        res += data.hour + (isChinese ? '小时' : 'h');
        len++;
    }
    if (data.min > 0 && (!length || len < length)) {
        res += data.min + (isChinese ? '分钟' : 'm');
        len++;
    }
    if (data.sec > 0 && (!length || len < length)) {
        res += data.sec + (isChinese ? '秒' : 's');
        len++;
    }
    return res;
}

/**格式化时间 返回小时分钟秒钟对象 */
export function formatTimeHMS(time: number) {
    let hour = ~~(time / 3600);
    time %= 3600;
    let min = ~~(time / 60);
    time %= 60;
    let sec = time;
    return { hour: hour, min: min, sec: sec };
}

/**
 * 格式化时间为小时
 * @param time 时间
 * @param type 时间单位
 */
export function formatHour(time: number, type: string = 'second'): string {
    if (type == 'micosecond') time /= 3600000;
    else if (type == 'second') time /= 3600;
    else if (type == 'minute') time /= 60;
    //取小数点后两位
    let tmp = ('' + time).split('.');
    return '' + tmp[0] + '.' + (tmp[1] ? tmp[1].substr(0, 2) : '0');
}

/**
 * 格式化时间(形式:'xxhxxmxxs')
 * @param time 秒
 * @param includeHour 是否包含小时(形式:'xx:xx:xx')
 */
export function formatMinuteUnit(time: number, includeHour: boolean = false): string {
    time = ~~time;
    let hour = ~~(time / 3600);
    if (includeHour) time %= 3600;
    let min = ~~(time / 60);
    let second = time % 60;
    let res = '';
    if (includeHour) {
        if (hour > 0) res += hour + 'h';
    }
    if (min > 0) {
        res += min + 'm';
    }
    if (second > 0) {
        res += second + 's';
    }
    return res;
}

/**
 * 格式化时间(形式:'xx:xx')
 * @param time 秒
 * @param includeHour 是否包含小时(形式:'xx:xx:xx')
 */
export function formatMinute(time: number, includeHour: boolean = false): string {
    time = ~~time;
    let hour = ~~(time / 3600);
    if (includeHour) time %= 3600;
    let min = ~~(time / 60);
    let second = time % 60;
    let res = '';
    if (includeHour) {
        if (hour < 10) res += '0';
        res += '' + hour + ':';
    }
    if (min < 10) res += '0';
    res += '' + min + ':';
    if (second < 10) res += '0';
    res += '' + second;
    return res;
}

export function zero(t) {
    return t > 9 ? t : ('0' + t);
}
export function formateDate(time: Date) {
    // 1. 获取到年 月 日 小时 分钟 秒
    //  并且给需要的时间 补0
    var year = time.getFullYear();
    var month = zero(time.getMonth() + 1);
    var day = zero(time.getDate());
    var hours = zero(time.getHours());
    var mins = zero(time.getMinutes());
    var seconds = zero(time.getSeconds());
    // 2. 拼接字符串
    return year + '/' + month + '/' + day + ' ' + hours + ':' + mins;
}


export function formatTime(time): string {
    var dateTimeStamp = new Date(time).getTime();
    var minute = 1000 * 60;
    var hour = minute * 60;
    var day = hour * 24;

    var month = day * 30;
    var year = month * 12;
    var now = new Date().getTime();
    var diffValue = now - dateTimeStamp;
    var result = ""
    if (diffValue < 0) {
        return "刚刚";
    }
    var monthC = diffValue / month;
    var weekC = diffValue / (7 * day);
    var dayC = diffValue / day;
    var hourC = diffValue / hour;
    var minC = diffValue / minute;
    var yearC = diffValue / year
    if (yearC >= 1) {
        return Math.floor(yearC) + "年前";
    }
    if (monthC >= 1) {
        result = Math.floor(monthC) + "月前";
    } else if (weekC >= 1) {
        result = Math.floor(weekC) + "周前";
    } else if (dayC >= 1) {
        result = Math.floor(dayC) + "天前";
    } else if (hourC >= 1) {
        result = Math.floor(hourC) + "小时前";
    } else if (minC >= 1) {
        result = Math.floor(minC) + "分钟前";
    } else {
        result = "刚刚";
    }

    return result;
}

export function date2BeijingUnixMilli(date: number | Date): Date {
    const eightHour = 8 * 3600 * 1000
    if (typeof date === "number") {
        const d = new Date(date)
        const offset = d.getTimezoneOffset() * 60 * 1000
        d.setTime(d.getTime() + offset + eightHour)
        return d
    } else {
        const offset = date.getTimezoneOffset() * 60 * 1000
        date.setTime(date.getTime() + offset + eightHour)
        return date
    }
}

//随机不重复int
export function randomInts(min, max, num) {
    var arr = [], t;
    function fn(i) {
        for (i; i < num; i++) {
            t = parseInt(Math.random() * (max - min + 1) + min);
            for (var k in arr) {
                if (arr[k] == t) {
                    fn(i);
                    break;
                }
            }
            arr[i] = t;
        }
    }
    fn(0);
    return arr;
}

export function segmentFunc(source: number, limit: number) {
    if (source > limit) return limit;
    else return source;
}

//移除数组中的某个元素
export function removeFromArr(arr: any[], element: any) {
    let idx: number = 0;
    idx = arr.indexOf(element);
    if (idx != -1) arr.splice(idx, 1);
}

//数组去重
export function uniqueArr(arr: number[]) {
    let result = [];
    let hash = {};
    for (let i = 0; i < arr.length; i++) {
        if (!hash[arr[i]]) {
            hash[arr[i]] = true;
            result.push(arr[i]);
        }
    }
    return result;
}

//字符串是否为空或空格
export function isNullEmptyOrSpace(str: string) {
    if (str == null) return true;
    return str.replace(/\s/g, '').length == 0;
}

//js对象转查询字符串
export function obj2Urlstr(params: any) {
    if (isApp()) {
        return Object.keys(params).map(key => {
            return "".concat(key, "=").concat(params[key].toString());
        }).join('&');
    } else {
        return Object.keys(params).map(key => {
            return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(params[key]));
        }).join('&');
    }
}

//map转object
export function mapToObj(strMap) {
    let obj = Object.create(null);
    strMap.forEach((v, k) => {
        obj[k] = v;
    });
    return obj;
}

//object转map
export function objToMap(obj, keyIsNum: boolean = false) {
    let strMap = new Map();
    Object.keys(obj).forEach(k => {
        if (keyIsNum) strMap.set(parseInt(k), obj[k]);
        else strMap.set(k, obj[k]);
    });
    return strMap;
}

//uint8转int32
export function byteToInt(value) {
    let r = 0;
    r = (value[0] << 24) + (value[1] << 16) + (value[2] << 8) + (value[3]);
    return r;
}

export function isValue(data: any): boolean {
    if (data !== undefined && data !== null) return true;
    else return false;
}


export function isApp() {
    return JSB;
}

export function isTT() {
    return window["tt"] ? true : false;
}

export function isQQ() {
    return window["qq"] ? true : false;
}

export function isDevelopment() {
    return DEV;
}



//spine换装
// export function changeSpineSlot(spine: sp.Skeleton, slotName: string, sprite: SpriteFrame): void {
//     var slot = spine.findSlot(slotName);
//     let texture = sprite.texture;
//     var attachment = slot.getAttachment();
//     let region = createSpineRegion(texture);
//     attachment.region = region;
//     if (attachment.setRegion) {
//         attachment.setRegion(region);
//     }
//     attachment.updateUVs();
// }

function createSpineRegion(texture) {
    let skeletonTexture = new sp["SkeletonTexture"]();
    skeletonTexture["_image"] = { width: texture.width, height: texture.height };
    skeletonTexture.setRealTexture(texture);

    let region = new sp["spine"].TextureAtlasRegion();
    region.width = texture.width;
    region.height = texture.height;
    region.originalWidth = texture.width;
    region.originalHeight = texture.height;
    region.rotate = false;
    region.u = 0;
    region.v = 0;
    region.u2 = 1;
    region.v2 = 1;
    region.texture = skeletonTexture;
    return region;
}

//显示当前场景里所有脚本类
export function showUiDebug() {
    var res = {};
    var node_num = 0;
    var node_info = {};
    var label_num = 0;
    var label_info = {};
    var mapChild = function (children) {
        if (!children || !children.length) {
            return;
        }
        for (var i = 0; i < children.length; ++i) {
            var child = children[i];
            if (!node_info[child.name]) {
                node_info[child.name] = 1;
            } else {
                node_info[child.name]++;
            }
            node_num++;
            if (!child.active || !child.isValid) {
                continue;
            }
            if (child._components) {
                child._components.forEach((c) => {
                    // if (!(c.node && c.node.isValid)) {
                    // // if (!c.enabled || !(c.node && c.node.isValid)) {
                    //     return;
                    // }
                    var name = c.__classname__;
                    if (!res[name]) {
                        res[name] = 0;
                    }
                    if (name == 'Label') {
                        label_num++;
                        if (!label_info[child.parent.name]) {
                            label_info[child.parent.name] = 1;
                        } else {
                            label_info[child.parent.name]++;
                        }
                    }
                    res[name]++;
                });
            }
            mapChild(child.children);
        }
    }
    mapChild(director.getScene().children);
    console.log('类详情:', res);
    console.log(`场景树上共有:${node_num}个node`);
    console.log(`节点详情:`, node_info);
    console.log(`场景树上共有:${label_num}个label`);
    console.log(`文本详情:`, label_info);
}

window['ui_test'] = showUiDebug;

export function showNodeDebug() {
    let tmp = director.getScene().getComponentsInChildren(Sprite);
    let count = 0;
    let t = [];
    let result = {};
    tmp.forEach(v => t.push(v.node));
    t.forEach(v => {
        if (!result[v.parent.name]) result[v.parent.name] = 1;
        else result[v.parent.name]++;
        count++;
    });
    console.log(`总共:${count}个节点,纹理父节点详情:`, result);
}

/**
 * 克隆一个对象
 */
export function clone(source: any) {
    return JSON.parse(JSON.stringify(source));
}

/**深拷贝对象 */
export function deepClone(obj: any) {
    if (!(obj instanceof Object)) {
        return;
    };
    let isArray = Array.isArray(obj);
    let cloneObj = isArray ? [...obj] : { ...obj };
    Reflect.ownKeys(cloneObj).forEach(key => {
        cloneObj[key] = obj[key] instanceof Object ? deepClone(obj[key]) : obj[key];
    });
    return cloneObj;
}

/**
 * 为对象注入数据
 */
export function inject(target, source, cloneInject: boolean = true) {
    if (cloneInject) {
        source = clone(source);
    }
    for (var key in target) {
        if (source.hasOwnProperty(key)) {
            target[key] = source[key];
        }
    }
}

//获取枚举长度
export function enumLength(source): number {
    let count = 0
    for (let item in source) {
        if (isNaN(Number(item))) count++;
    }
    return count;
}

/**
 * 权重概率计算
 */
export function weightRandom(weightArray: number[]): number {
    let randomList = [];
    for (let index = 0; index < weightArray.length; index++) {
        for (let j = 0; j < weightArray[index]; j++) {
            randomList.push(index);
        }
    }
    let randomValue = Math.floor(Math.random() * randomList.length);
    return randomList.length ? randomList[randomValue] : -1;
}

export function setDownloaderRemoteAddress(url: string) {
    if (assetManager.downloader["_remoteServerAddress"]) {
        assetManager.downloader["_remoteServerAddress"] = url;
    }
}


export function getTimeStamp() {
    var date = new Date();
    return date.getTime();
}

export function getZeroTimeStamp() {
    const date = new Date(new Date().setHours(0, 0, 0, 0)); //获取当天零点的时间
    return date.getTime();
}

/**
 * 点击震动
 */
export function getUrlParamMap(): any {
    //正式使用
    if (!location.search && !location.hash) return null;
    var params = {};
    var parse = function (str) {
        var fragments = str.split('&');
        for (var i = 0; i < fragments.length; i++) {
            var pairs = fragments[i].split('=');
            params[pairs[0]] = decodeURIComponent(pairs[1]);
        }
    };
    if (location.hash) parse(location.hash.substr(1));
    if (location.search) {
        var idx = location.search.indexOf("?");
        if (idx != -1) {
            var hash = location.search.substr(idx + 1);
            hash = hash.split('!')[0];
            parse(hash);
        }
    }
    return params;
}


//打印日志的属性装饰器
export function log(target: any, propertyKey: string) {
    let value = target[propertyKey];
    // 用来替换的getter
    const getter = function () {
        console.log(`Get ${propertyKey} returned ${value}`);
        return value;
    }
    // 用来替换的setter
    const setter = function (newVal) {
        console.log(`Set ${propertyKey} to ${newVal}`);
        value = newVal;
    };
    // 替换属性，先删除原先的属性，再重新定义属性
    if (delete this[propertyKey]) {
        Object.defineProperty(target, propertyKey, {
            get: getter,
            set: setter,
            enumerable: true,
            configurable: true
        });
    }
}

//序列化组件属性装饰器
export function serializable(target: any, propertyKey: string) {
    if (!target.constructor["serializeKeys"]) {
        target.constructor["serializeKeys"] = [];
    }
    let keys = target.constructor["serializeKeys"];
    keys.push(propertyKey);
}

//系统信息
export class SystemInfo {
    system: string;//	操作系统版本	"11.4" | "8.0.0"	1.0.0
    platform: string;//	操作系统类型	"ios" | "android"	1.0.0
    brand: string;//	手机品牌	"Apple" | "Xiaomi"	1.0.0
    model: string;//	手机型号		1.0.0
    version: string;//	宿主 App 版本号（宿主指今日头条、抖音等）	6.7.8	1.0.0
    appName?: string;//	宿主 APP 名称	"Toutiao"	1.0.0
    SDKVersion: string;//	客户端基础库版本	"1.0.0"	1.0.0
    screenWidth: number;//	屏幕宽度		1.0.0
    screenHeight: number;//	屏幕高度		1.0.0
    windowWidth: number;//	可使用窗口宽度		1.0.0
    windowHeight: number;//	可使用窗口高度		1.0.0
    pixelRatio: number;//	设备像素比		1.0.0
    statusBarHeight: number;//	状态栏的高度，单位 px		1.0.0
    safeArea?: {
        left: number;//安全区域左上角横坐标
        right: number;//安全区域右下角横坐标
        top: number;//安全区域左上角纵坐标
        bottom: number;//安全区域右下角纵坐标
        width: number;//安全区域的宽度，单位逻辑像素
        height: number;//安全区域的高度，单位逻辑像素
    }
}

export const arabicNumToCNNum = (digit: number): string => {
    const chineseDigitTable = [
        '零',
        '一',
        '二',
        '三',
        '四',
        '五',
        '六',
        '七',
        '八',
        '九',
        '十',
        '百',
        '千',
        '万',
        '亿',
        '万亿'
    ] as const;

    const ploy = {
        /**
         * @description 小于100的数转换
         * @param digital
         * @returns
         */
        ltHundred(digital: number) {
            if (digit <= 10) {
                return chineseDigitTable[digit];
            }

            const ten = Math.trunc(digital / 10);
            const cnDigit =
                (ten > 1 ? chineseDigitTable[ten] : '') + chineseDigitTable[10];

            const num = digital % 10;
            if (num === 0) {
                return cnDigit;
            }

            return cnDigit + chineseDigitTable[num];
        },
        /**
         * @description 小于1000的数转换
         * @param digital
         * @returns
         */
        ltThousand(digital: number) {
            let cnDigit =
                chineseDigitTable[Math.trunc(digital / 100)] + chineseDigitTable[11];

            const num = digital % 100;
            if (num === 0) {
                return cnDigit;
            }

            if (num < 10) {
                return cnDigit + chineseDigitTable[0] + chineseDigitTable[num];
            }

            // 处理110/214等情况 => 二百一十四
            if (num >= 10 && num < 20) {
                cnDigit += chineseDigitTable[1] + chineseDigitTable[10];
                if (num > 10) {
                    cnDigit += chineseDigitTable[num - 10];
                }

                return cnDigit;
            }

            return cnDigit + ploy.ltHundred(num);
        },
        /**
         * 小于一万的数转换
         * @param digital
         * @returns
         */
        ltTenThousand(digital: number) {
            const cnDigit =
                chineseDigitTable[Math.trunc(digital / 1000)] + chineseDigitTable[12];

            const num = digital % 1000;
            if (num === 0) {
                return cnDigit;
            }
            if (num < 10) {
                return cnDigit + chineseDigitTable[0] + chineseDigitTable[num];
            }
            if (num < 100) {
                if (num === 10) {
                    return (
                        cnDigit +
                        chineseDigitTable[0] +
                        chineseDigitTable[1] +
                        chineseDigitTable[10]
                    );
                }
                return cnDigit + chineseDigitTable[0] + ploy.ltHundred(num);
            }

            return cnDigit + ploy.ltThousand(num);
        },
        /**
         * @description 亿到万亿
         * @param digital
         * @returns
         */
        gtBillion(digital: number) {
            let padStart = (str: string, targetLength: number, padString: string) => {
                if (str.length >= targetLength) {
                    return str;
                }

                let padding = '';
                while (padding.length < (targetLength - str.length)) {
                    padding += padString;
                }

                return padding + str;
            }
            let digitString = digital.toString();
            const digitLen = digitString.length;
            if (digitLen > 16 || digitLen < 5) {
                return '';
            }
            if (digitLen <= 8) {
                digitString = padStart(digitString, 8, '0');
            } else if (digitLen <= 12) {
                digitString = padStart(digitString, 12, '0');
            } else {
                digitString = padStart(digitString, 16, '0');
            }

            // 将大数字拆分，例如：123456789 => ['0001', '2345', '6789']
            const digits = digitString
                .split(/([0-9]{4})/)
                .filter((item) => item !== '');

            let cnDigit = '';
            const len = digits.length;
            digits.forEach((item, index) => {
                const num = Number(item);
                let text = '';
                if (num !== 0) {
                    text = arabicNumToCNNum(num);
                }

                if (index !== 0) {
                    // 这种情况 [0002, 0001] [0010, 3400] 都需要补零
                    if (
                        (num > 0 && num < 1000) ||
                        digits[index - 1].lastIndexOf('0') === 3
                    ) {
                        cnDigit += chineseDigitTable[0];
                    }
                }

                // 数字小于一亿 => 1万至9999万...
                if (len === 2) {
                    if (index === 0) {
                        cnDigit = text + chineseDigitTable[13];
                        return;
                    }

                    cnDigit += text;
                    return;
                }

                // 数字小于一万亿
                if (len === 3) {
                    if (index === 0) {
                        cnDigit = text + chineseDigitTable[14];
                        return;
                    }

                    if (index === 1 && num !== 0) {
                        cnDigit += text + chineseDigitTable[13];
                        return;
                    }

                    cnDigit += text;
                    return;
                }

                // 千万亿级别
                if (len === 4) {
                    if (index === 0) {
                        cnDigit = text + chineseDigitTable[15];
                        return;
                    }

                    if (index === 1 && num !== 0) {
                        cnDigit += text + chineseDigitTable[14];
                        return;
                    }

                    if (index === 2 && num !== 0) {
                        cnDigit += text + chineseDigitTable[13];
                        return;
                    }

                    cnDigit += text;
                    return;
                }
            });

            return cnDigit;
        }
    };

    let chineseDigit = '';
    digit = digit | 0;
    if (digit < 0) {
        chineseDigit += '负';
        digit = Math.abs(digit);
    }
    if (digit < 100) {
        return chineseDigit + ploy.ltHundred(digit);
    }
    if (digit < 1000) {
        return chineseDigit + ploy.ltThousand(digit);
    }
    if (digit < 10000) {
        return chineseDigit + ploy.ltTenThousand(digit);
    }

    chineseDigit += ploy.gtBillion(digit);

    return chineseDigit;
};